package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.EcologyPoolDaoRankConfDao;
import com.sc.nft.dao.EcologyPoolDaoRankDao;
import com.sc.nft.dao.EcologyPoolDaoRankIncomeConfDao;
import com.sc.nft.entity.*;
import com.sc.nft.entity.vo.ExcellentBrandRankingVO;
import com.sc.nft.entity.vo.ecologypool.EcologyPoolDaoRankExcelVO;
import com.sc.nft.entity.vo.ecologypool.EcologyPoolDaoRankPageVO;
import com.sc.nft.entity.vo.ecologypool.EcologyPoolExcellentBrandUploadAllVO;
import com.sc.nft.entity.vo.ecologypool.EcologyPoolExcellentBrandUploadVo;
import com.sc.nft.enums.EcologyPoolLinkTypeEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.EcologyPoolDaoRankService;
import com.sc.nft.service.EcologyPoolService;
import com.sc.nft.service.UserCreatorInfoService;
import com.sc.nft.service.UserInfoService;
import com.sc.nft.sup.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 生态池-品牌榜服务接口实现
 *
 * @author jinpinhai
 * @description Generator
 * @since 2024-07-17 11:00:11
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class EcologyPoolDaoRankServiceImpl implements EcologyPoolDaoRankService {

    private final EcologyPoolDaoRankDao ecologyPoolDaoRankDao;
    private final EcologyPoolDaoRankConfDao ecologyPoolDaoRankConfDao;
    private final EcologyPoolDaoRankIncomeConfDao ecologyPoolDaoRankIncomeConfDao;
    private final EcologyPoolService ecologyPoolService;
    private final UserInfoService userInfoService;
    private final UserCreatorInfoService userCreatorInfoService;

    @Override
    public IPage<EcologyPoolDaoRankPageVO> daoRankPage(int pageNo, int pageSize, Long rankConfId) {
        EcologyPoolDaoRank maxRankDate = ecologyPoolDaoRankDao.getMaxRankDate(rankConfId);
        if (ObjectUtil.isEmpty(maxRankDate)) {
            return new Page<>(pageNo, pageSize);
        }
        Page<EcologyPoolDaoRank> ecologyPoolDaoRankPage = ecologyPoolDaoRankDao.pageDaoRank(pageNo, pageSize, rankConfId, maxRankDate);
        List<Long> userIds = ecologyPoolDaoRankPage.getRecords().stream().map(EcologyPoolDaoRank::getUserId).filter(ObjectUtil::isNotNull).collect(Collectors.toList());
        Map<Long, UserInfo> userInfoMap = userInfoService.getByIdListToMap(userIds);
        return ecologyPoolDaoRankPage.convert(x -> {
            EcologyPoolDaoRankPageVO ecologyPoolDaoRankPageVO = new EcologyPoolDaoRankPageVO();
            ecologyPoolDaoRankPageVO.setSort(x.getSort());
            ecologyPoolDaoRankPageVO.setSortChange(x.getSortChange());
            ecologyPoolDaoRankPageVO.setDaoId(x.getDaoId());
            ecologyPoolDaoRankPageVO.setRankName(x.getRankName());
            ecologyPoolDaoRankPageVO.setContribution(x.getContribution());
            UserInfo userInfo = userInfoMap.get(x.getUserId());
            if (ObjectUtil.isNotNull(userInfo)) {
                ecologyPoolDaoRankPageVO.setUserId(x.getUserId());
                ecologyPoolDaoRankPageVO.setUserTel(userInfo.getUserTel());
                ecologyPoolDaoRankPageVO.setNickName(userInfo.getNickName());
            }
            ecologyPoolDaoRankPageVO.setPrizeRatio(x.getPrizeRatio());
            ecologyPoolDaoRankPageVO.setNewUserCount(x.getNewUserCount());
            ecologyPoolDaoRankPageVO.setEcologySmelting(x.getEcologySmelting());
            ecologyPoolDaoRankPageVO.setCashIn(x.getCashIn());
            ecologyPoolDaoRankPageVO.setCashOut(x.getCashOut());
            return ecologyPoolDaoRankPageVO;
        });
    }

    @Override
    public List<EcologyPoolDaoRankExcelVO> daoRankExcel(Long rankConfId) {
        EcologyPoolDaoRank maxRankDate = ecologyPoolDaoRankDao.getMaxRankDate(rankConfId);
        if (ObjectUtil.isEmpty(maxRankDate)) {
            return new ArrayList<>();
        }
        List<EcologyPoolDaoRank> ecologyPoolDaoRanks = ecologyPoolDaoRankDao.listByRankConfId(rankConfId, maxRankDate);
        List<Long> userIds = ecologyPoolDaoRanks.stream().map(EcologyPoolDaoRank::getUserId).filter(ObjectUtil::isNotNull).collect(Collectors.toList());
        Map<Long, UserInfo> userInfoMap = userInfoService.getByIdListToMap(userIds);
        List<EcologyPoolDaoRankExcelVO> ecologyPoolDaoRankExcelVOS = new ArrayList<>();
        for (EcologyPoolDaoRank ecologyPoolDaoRank : ecologyPoolDaoRanks) {
            EcologyPoolDaoRankExcelVO ecologyPoolDaoRankExcelVO = new EcologyPoolDaoRankExcelVO();
            ecologyPoolDaoRankExcelVO.setSort(ecologyPoolDaoRank.getSort());
            ecologyPoolDaoRankExcelVO.setDaoId(ecologyPoolDaoRank.getDaoId());
            ecologyPoolDaoRankExcelVO.setRankName(ecologyPoolDaoRank.getRankName());
            ecologyPoolDaoRankExcelVO.setContribution(ecologyPoolDaoRank.getContribution());
            UserInfo userInfo = userInfoMap.get(ecologyPoolDaoRank.getUserId());
            if (ObjectUtil.isNotNull(userInfo)) {
                ecologyPoolDaoRankExcelVO.setUserId(userInfo.getId());
                ecologyPoolDaoRankExcelVO.setUserTel(userInfo.getUserTel());
                ecologyPoolDaoRankExcelVO.setNickName(userInfo.getNickName());
            }
            if (ObjectUtil.isNotNull(ecologyPoolDaoRank.getPrizeRatio())) {
                ecologyPoolDaoRankExcelVO.setPrizeRatio(ecologyPoolDaoRank.getPrizeRatio() + "%");
            } else {
                ecologyPoolDaoRankExcelVO.setPrizeRatio("0%");
            }
            ecologyPoolDaoRankExcelVO.setNewUserCount(ecologyPoolDaoRank.getNewUserCount());
            ecologyPoolDaoRankExcelVO.setEcologySmelting(ecologyPoolDaoRank.getEcologySmelting());
            ecologyPoolDaoRankExcelVO.setCashIn(ecologyPoolDaoRank.getCashIn());
            ecologyPoolDaoRankExcelVO.setCashOut(ecologyPoolDaoRank.getCashOut());
            ecologyPoolDaoRankExcelVOS.add(ecologyPoolDaoRankExcelVO);
        }
        return ecologyPoolDaoRankExcelVOS;
    }


    @Override
    public EcologyPoolExcellentBrandUploadAllVO excellentBrandUpload(MultipartFile file) throws IOException {
        EcologyPoolExcellentBrandUploadAllVO vo = new EcologyPoolExcellentBrandUploadAllVO();
        String fileName = file.getOriginalFilename();
        if (StringUtils.isBlank(fileName)) {
            throw new GlobalRunTimeException("文件名称为空!");
        }
        String extension = FilenameUtils.getExtension(fileName);

        InputStream inputStream = file.getInputStream();
        Workbook wb;
        if ("xls".equals(extension)) {
            wb = new HSSFWorkbook(inputStream);
        } else if ("xlsx".equals(extension)) {
            wb = new XSSFWorkbook(inputStream);
        } else {
            throw new GlobalRunTimeException(ErrorCode.WRONG_FILE_TYPE);
        }
        Sheet sheet = wb.getSheetAt(0);
        //获取最大行数
        int rowNum = sheet.getPhysicalNumberOfRows();
        //最多200条
        if (rowNum > 201) {
            throw new GlobalRunTimeException("最大支持上传200条");
        }

        List<EcologyPoolExcellentBrandUploadVo> list = new ArrayList<>();
        //解析excel内容
        doGetExcellentBrandUpload(vo, rowNum, sheet, list);
        List<Long> daoIds = list.stream().map(EcologyPoolExcellentBrandUploadVo::getDaoId).filter(ObjectUtil::isNotNull).collect(Collectors.toList());
        //校验行数据
        checkRow(daoIds, list);
        //填充excel内容
        vo.setUploadList(doSetExcelContent(vo, list, daoIds));
        return vo;
    }

    private void checkRow(List<Long> daoIds, List<EcologyPoolExcellentBrandUploadVo> list) {
        Map<Long, UserCreatorInfo> daoByIdsToMap = userCreatorInfoService.getDaoByIdsToMap(daoIds);
        for (EcologyPoolExcellentBrandUploadVo ecologyPoolExcellentBrandUploadVo : list) {
            UserCreatorInfo userCreatorInfo = daoByIdsToMap.get(ecologyPoolExcellentBrandUploadVo.getDaoId());
            if (ObjectUtil.isNull(userCreatorInfo)) {
                throw new GlobalRunTimeException(ecologyPoolExcellentBrandUploadVo.getDaoId() + "品牌id不存在");
            }
        }
    }

    private List<EcologyPoolExcellentBrandUploadVo> doSetExcelContent(EcologyPoolExcellentBrandUploadAllVO vo, List<EcologyPoolExcellentBrandUploadVo> list, List<Long> daoIds) {
        Map<Long, EcologyPool> ecologyPoolMap = ecologyPoolService.getDaoByIdsToMap(daoIds);
        int successCount = 0;
        List<EcologyPoolExcellentBrandUploadVo> newList = new ArrayList<>();
        for (EcologyPoolExcellentBrandUploadVo ecologyPoolExcellentBrandUploadVo : list) {
            ecologyPoolExcellentBrandUploadVo.setLinkType(EcologyPoolLinkTypeEnum.POINTS);
            ecologyPoolExcellentBrandUploadVo.setLinkTypeName(EcologyPoolLinkTypeEnum.POINTS.getDesc());
            ecologyPoolExcellentBrandUploadVo.setLinkCount(ecologyPoolExcellentBrandUploadVo.getLinkCount());
            EcologyPool ecologyPool = ecologyPoolMap.get(ecologyPoolExcellentBrandUploadVo.getDaoId());
            if (ObjectUtil.isNotNull(ecologyPool)) {
                ecologyPoolExcellentBrandUploadVo.setCurrentLinkCount(ecologyPool.getLinkCount());
            }
            newList.add(ecologyPoolExcellentBrandUploadVo);
            successCount++;
        }
        vo.setSuccessCount(successCount);
        return newList;
    }

    private void doGetExcellentBrandUpload(EcologyPoolExcellentBrandUploadAllVO vo, int rowNum, Sheet sheet, List<EcologyPoolExcellentBrandUploadVo> list) {
        int allCount = 0;
        for (int i = 1; i < rowNum; i++) {
            allCount++;
            EcologyPoolExcellentBrandUploadVo ecologyPoolExcellentBrandUploadVo = new EcologyPoolExcellentBrandUploadVo();
            Row row = sheet.getRow(i);
            Cell idCell = row.getCell(0);
            if (ObjectUtil.isNull(idCell) || idCell.getCellType() == CellType.BLANK) {
                throw new GlobalRunTimeException("第" + i + "行品牌id不能为空");
            }
            if (idCell.getCellType() != CellType.STRING) {
                throw new GlobalRunTimeException("第" + i + "行积分只支持文本格式,请调整");
            }
            String id = idCell.getStringCellValue().trim();
            ecologyPoolExcellentBrandUploadVo.setDaoId(Long.parseLong(id));

            Cell nameCell = row.getCell(1);
            if (ObjectUtil.isEmpty(nameCell) || StringUtils.isBlank(nameCell.getStringCellValue())) {
                throw new GlobalRunTimeException("第" + i + "行品牌名称不能为空");
            }
            String name = nameCell.getStringCellValue().trim();
            ecologyPoolExcellentBrandUploadVo.setDaoName(name);

            Cell linkCountCell = row.getCell(2);
            if (ObjectUtil.isNull(linkCountCell) || linkCountCell.getCellType() == CellType.BLANK) {
                ecologyPoolExcellentBrandUploadVo.setLinkCount(0L);
            } else if (linkCountCell.getCellType() != CellType.STRING) {
                throw new GlobalRunTimeException("第" + i + "行积分只支持文本格式,请调整");
            } else {
                String count = linkCountCell.getStringCellValue();
                if (hasDecimalPart(count)) {
                    throw new GlobalRunTimeException("第" + i + "行积分只能为整数");
                }
                if (!StringUtils.isNumeric(count)) {
                    ecologyPoolExcellentBrandUploadVo.setLinkCount(0L);
                } else {
                    ecologyPoolExcellentBrandUploadVo.setLinkCount(Long.parseLong(count));
                }
            }
            list.add(ecologyPoolExcellentBrandUploadVo);
        }
        vo.setAllCount(allCount);
    }

    public static boolean hasDecimalPart(String numberStr) {
        try {
            BigDecimal bd = new BigDecimal(numberStr);
            return bd.scale() > 0;
        } catch (NumberFormatException e) {
            // 处理异常：例如字符串不是有效的数字格式
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBatchExchequer(List<ExcellentBrandRankingVO> batch) {
        ecologyPoolDaoRankDao.saveBatchExchequer(batch);
    }

    /**
     * 处理本期排名
     *
     * @param configId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rankProcessing(Long configId) {
        EcologyPoolDaoRankConf ecologyPoolDaoRankConf = ecologyPoolDaoRankConfDao.getById(configId);
        if (BeanUtil.isEmpty(ecologyPoolDaoRankConf)) {
            return;
        }
        // 根据配置id获取排名配置信息,根据排名的配置信息,去获取本期的排名数据,把排名数据进行处理,如果遇到了排名数据出现了多条的情况,则把排名进行顺延.
        List<EcologyPoolDaoRankIncomeConf> ecologyPoolDaoRankIncomeConfs = ecologyPoolDaoRankIncomeConfDao.getConfigId(configId);
        if (CollUtil.isEmpty(ecologyPoolDaoRankIncomeConfs)) {
            return;
        }
        ecologyPoolDaoRankIncomeConfs.forEach(ecologyPoolDaoRankIncomeConf -> {
            List<Long> userIdExcludeList = new ArrayList<>();
            // 根据配置从里面找到对应的排名数据,每使用一个排名就把对应排名的id加入到排除list里面,否则的话会出现重复排名的情况
            for (int i = 0; i < ecologyPoolDaoRankIncomeConf.getEndRank() - ecologyPoolDaoRankIncomeConf.getStartRank(); i++) {
                EcologyPoolDaoRank ecologyPoolDaoRank = ecologyPoolDaoRankDao.listByRankConfIdAndcContributionThreshold(configId, ecologyPoolDaoRankConf.getContributionThreshold() != null ? ecologyPoolDaoRankConf.getContributionThreshold() : BigDecimal.ZERO, userIdExcludeList, ecologyPoolDaoRankIncomeConf.getContributionThreshold() != null ? ecologyPoolDaoRankIncomeConf.getContributionThreshold() : BigDecimal.ZERO);
                if (BeanUtil.isNotEmpty(ecologyPoolDaoRank)) {
                    // 获取今日排名和昨日排名,是否有差距
                    // 向前偏移一天
                    EcologyPoolDaoRank compareDaoRank = ecologyPoolDaoRankDao.compareDaoRank(ecologyPoolDaoRank.getDaoId(), ecologyPoolDaoRank.getUserId(), DateUtil.offsetDay(DateUtil.date(), -1));
                    EcologyPoolDaoRank result = new EcologyPoolDaoRank();
                    result.setId(ecologyPoolDaoRank.getId());
                    result.setSort(ecologyPoolDaoRankIncomeConf.getStartRank() + i + 1L);
                    if (BeanUtil.isNotEmpty(compareDaoRank)) {
                        // 前一期也有排名,那就计算排名差值是上升还是下降
                        result.setSortChange(Convert.toInt(result.getSort() - compareDaoRank.getSort()));
                    } else {
                        result.setSortChange(-1);
                    }
                    result.setHasSort(Boolean.TRUE);
                    result.setShowStatus(Boolean.TRUE);
                    result.setPrizeRatio(ecologyPoolDaoRankIncomeConf.getPrizeRatio());
                    result.updateById();
                    userIdExcludeList.add(ecologyPoolDaoRank.getDaoId());
                } else {
                    EcologyPoolDaoRank result = new EcologyPoolDaoRank();
                    result.setEcologyPoolDaoRankConfId(configId);
                    result.setRankDate(DateUtil.date());
                    result.setDaoId(0L);
                    result.setContribution(BigDecimal.ZERO);
                    if (ecologyPoolDaoRankIncomeConf.getContributionThreshold() != null) {
                        result.setRankName(StrUtil.format("上榜条件：贡献值>={}", ecologyPoolDaoRankIncomeConf.getContributionThreshold().setScale(2, BigDecimal.ROUND_DOWN)));
                    } else {
                        result.setRankName(StrUtil.format("暂无入榜"));
                    }
                    result.setSort(ecologyPoolDaoRankIncomeConf.getStartRank() + i + 1L);
                    result.setHasSort(Boolean.FALSE);
                    result.setShowStatus(Boolean.TRUE);
                    result.setNewUserCount(0);
                    result.setSortChange(0);
                    result.setEcologySmelting(BigDecimal.ZERO);
                    result.setCashIn(BigDecimal.ZERO);
                    result.setCashOut(BigDecimal.ZERO);
                    result.insert();
                }
            }
        });

    }
}